因開發過程細節較多會分成兩篇來說明。
(1)新增餐廳實評頁面檔案
路徑 src / views / front 底下新增 CommentView.vue 檔案。 html 架構先建立同「Day8-試試Vue3-會員登入後轉跳主頁」的導覽(nav)。
(2)新增路由
路徑 src / router / index.js 寫入以下語法將餐廳實評頁面建為新路由。登入後才可到會員功能頁所以路徑是 login / CommentView 。
const router = createRouter({
...
routes: [
...
{
path: '/login/comment',
component: () => import('../views/front/CommentView.vue')
},
]
})
(3)編輯餐廳實評檔案
本小節說明檔案 CommentView.vue 的開發內容。
(3-1)前置作業
1.調用 Pinia store 資料<script></script>
將 LoginStore.js 檔裡的 useLoginStore 方法取出。透過 computed 監控資料更動時就重新渲染畫面的特性,把 Pinia store 剛更新的會員 name 、 email 、 id 給顯示。再運用 mapState 取用 Pinia store 資料。
2.取得網路請求 axios 的路徑
created 裡的 apiUserResUrl 與 apiUserResIdUrl 是網路請求的路徑。路徑在頁面載入時被使用,為使方法中所有函式能取用該變數(全域變數),將之定義於此。created 是 Vue 生命週期中實例創建完成階段,可訪問 data 、 computed 、 watch、 methods 上的方法和數據。此時可把 apiUserResUrl 與 apiUserResIdUrl 在 data 裡的初始值給重新賦值。
(3-2)導出的資料<script></script>
中資料實體建立以下屬性。
(3-3)頁面下面區塊(卡片區塊)
參考 bootstrap5「卡片」來寫 html 結構。該區塊的操作情境請參考上一篇「Day25-試試Vue3-規劃餐廳實評的頁面」。
頁面載入時執行 userPocket() 函式,取得該會員的會員餐廳 API 資料,並使用 v-for="(item, index) in userResList"
將口袋餐廳頁面所選的清單進行多筆資料渲染。此處需取得該筆資料的索引值(index)才能在點選每張卡片裡的「查看實評」鈕時展開下方被折疊的評論區塊,否則按了任一張卡片的「查看實評」鈕會開啟所有卡片被折疊的區塊。參數設定請參考 bootstrap5「折疊」說明。
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
。點選任一張卡片時會觸發方法裡的 selectCard(item) 函式
selectCardList.cardComment = ""
。<template>
<div class="container">
...
<section class="row">
<div class="col-3" v-for="(item, index) in userResList" v-bind:key="item">
<a @click="selectCard(item)">
<div class="card">
<h2 class="card-header">{{ item.type }}</h2>
<div class="card-body">
<h3 class="card-title">{{ item.brandName }}</h3>
<p class="card-text">{{ item.address }}</p>
<p>
<button
class="btn btn-warning"
type="button"
data-bs-toggle="collapse"
:data-bs-target="'#collapseExample' + index"
aria-expanded="false"
:aria-controls="'collapseExample' + index">
查看實評
</button>
</p>
<div class="collapse" :id="'collapseExample' + index">
<div class="card card-body">
{{ item.comment }}
</div>
</div>
</div>
</div>
</a>
</div>
</section>
</div>
</template>
<script>
import axios from "axios";
import { mapState } from "pinia";
// 定義好的 store 賦值給變數 useLoginStore
// 在元件中引入並呼叫 useLoginStore() 來訪問 store
import { useLoginStore } from "../../components/LoginStore.js";
export default {
data() {
return {
userResList: [],
selectCardList: {
cardBrandName: "",
cardType: "",
cardAddress: "",
cardComment: "",
},
commentDisabled: true,
apiUserResUrl: "",
apiUserResIdUrl: "",
};
},
methods: {
userPocket() {
axios
.get(this.apiUserResUrl)
.then((res) => {
console.log(res);
this.userResList = res.data[0].userRestaurants;
})
.catch((error) => {
console.log(error);
});
},
selectCard(item) {
// 允許對餐廳評論操作
this.commentDisabled = false;
console.log(item);
this.selectCardList.cardBrandName = item.brandName;
this.selectCardList.cardType = item.type;
this.selectCardList.cardAddress = item.address;
if (item.comment) {
this.selectCardList.cardComment = item.comment;
} else {
// 將上一次選擇的卡片評論給重置
this.selectCardList.cardComment = "";
}
},
},
created() {
this.apiUserResUrl = `http://localhost:3002/userRes?email=${this.userEmail}`;
this.apiUserResIdUrl = `http://localhost:3002/userRes/${this.userId}`;
},
mounted() {
this.userPocket();
},
// 監聽data
computed: {
...mapState(useLoginStore, {
// 'name' 是 store 中的狀態名,'userName' 是在組件中的名稱
userName: (state) => state.name,
userEmail: (state) => state.email,
userId: (state) => state.id,
}),
},
};
</script>